package com.mgq.algorithm.dp;

/**
 * 给定一个整型数组arr，代表数值不同的纸牌排成一条线。 玩家A和玩家B依次拿走每张纸
 * 牌，规定玩家A先拿，玩家B后拿，但是每个玩家每次只能拿走最左或最右的纸牌，玩家A
 * 和玩家B都绝项聪明。请返回最后获胜者的分数。
 * [举例]
 * arr=[1,2, 100, 4]。
 * 开始时，玩家A只能拿走1或4。如果开始时玩家A拿走1，则排列变为[2, 100, 4]，接下来
 * 玩家B可以拿走2或4，然后继续轮到玩家A...
 * 如果开始时玩家A拿走4，则排列变为[1, 2, 100]，接下来玩家B可以拿走1或100，然后继
 * 续轮到玩家A....
 * 玩家A作为绝项聪明的人不会先拿4，因为拿4之后，玩家B将拿走100。所以玩家A会先拿1,
 * 让排列变为[2, 100, 4]，接下来玩家B不管怎么选，100都会被玩家A拿走。玩家A会获胜,
 * 分数为101。所以返回101。
 * arr=[1, 100, 2]。
 * 开始时，玩家A不管拿1还是2，玩家B作为绝顶聪明的人，都会把100拿走。玩家B会获胜，
 * 分数为100。所以返回100。
 */
public class MaxScore2 {

    /**
     * 返回A先手,B后手的最大分数
     *
     * @param array
     * @return
     */
    public static int maxScore(int[] array) {
        return Math.max(f(array, 0, array.length - 1), s(array, 0, array.length - 1));
    }

    /**
     * 先手函数
     *
     * @param array
     * @param L
     * @param R
     * @return
     */
    public static int f(int[] array, int L, int R) {
        //剩余一个硬币,先手就拿走了
        if (L == R) {
            return array[L];
        }
        //先手 返回的是 先手左边的值+后手左边的值 和先手右边的值+后手右边的值的 2个取最大值
        return Math.max(array[L] + s(array, L + 1, R), array[R] + s(array, L, R - 1));
    }

    /**
     * 后手函数
     *
     * @param array
     * @param L
     * @param R
     * @return
     */
    public static int s(int[] array, int L, int R) {
        //剩余1个,后手肯定就拿不到了,因为先手肯定会拿的
        if (L == R) {
            return 0;
        }
        return Math.min(f(array, L + 1, R), f(array, L, R - 1));
    }

    /**
     * dp版本
     * @param array

     * @return
     */
    public static int dp(int[] array) {
        int[][] first = new int[array.length][array.length];
        int[][] second = new int[array.length][array.length];
        //设置对角线, 对角线的值等于
        for (int i = 0; i <array.length ; i++) {
            first[i][i]=array[i];
        }
        int row=0;
        int col=1;
        while (col < array.length) {
            int i=row;
            int j=col;
            while (i < array.length && j < array.length) {
                int left = array[i] + second[i + 1][j];
                int right = array[j] + second[i][j - 1];
                first[i][j]=Math.max(left,right);
                second[i][j] = Math.min(first[i + 1][j], first[i][j - 1]);
                i++;
                j++;
            }
            col++;
        }
        return Math.max(first[0][array.length - 1], second[0][array.length - 1]);
    }

    public static void main(String[] args) {
        int[] array=new int[]{3, 100, 4,50};
        int win = dp(array);
        int win2 = maxScore(array);
        System.out.println(win);
        System.out.println(win2);
    }
}
